// 
// Bachelor of Software Engineering
// Media Design School
// Auckland
// New Zealand
//
// (c) 2005 - 2014 Media Design School
//
// File Name	: CCardStack.h
// Desrciption	: CCardStack declaration file.
// Author(s)	: Hayden Asplet.
// Mail			: hayden.asplet@mediadesignschool.com
//

// PCH
#include "SolitaireStd.h"

// Library Includes
#include <algorithm>

// This Include
#include "CardStack.h"

// Local Includes

CCardStack::CCardStack()
	:m_position(CPoint(0,0)),
	m_iOffset(0),
	m_eDirection(keDown)
{

}

CCardStack::CCardStack(const CPoint& _krPosition, int _iOffset, const EStackDirection& _kreDirection)
	:m_position(_krPosition),
	m_iOffset(_iOffset),
	m_eDirection(_kreDirection)
{

}

CCardStack::CCardStack(const CCardStack& _krStack)
	:m_position(_krStack.GetPosition()),
	m_iOffset(_krStack.GetOffset()),
	m_eDirection(_krStack.GetDirection())
{
	// Transfer cards.
	for(int i = 0; i < _krStack.Size(); ++i) {
		m_cards.push_back(_krStack[i]);
	}
}

CCardStack::~CCardStack()
{

}

bool CCardStack::IsOverlapping(const CPoint& _krPosition)
{
	if(IsEmpty()) {
		CRect defaultRect(m_position.m_iX, m_position.m_iY, g_kiCARD_WIDTH, g_kiCARD_HEIGHT);

		return defaultRect.IsInBounds(_krPosition);
	}
	else {
		return Peek().GetRect().IsInBounds(_krPosition);
	}
	
	return false;
}

bool CCardStack::IsOverlapping(const CRect& _krRect)
{
	if(IsEmpty()) {
		CRect defaultRect(m_position.m_iX, m_position.m_iY, g_kiCARD_WIDTH, g_kiCARD_HEIGHT);

		return IsIntersecting(defaultRect, _krRect);
	}
	else {
		return IsIntersecting(Peek().GetRect(), _krRect);
	}
}

int CCardStack::GetOverlapping(const CPoint& _krPosition)
{
	for(int i = Size() - 1; i >= 0; --i) {
		if(m_cards[i].GetRect().IsInBounds(_krPosition)) {
			return i;
		}
	}

	// No card found that overlaps the given position, return -1 to signify error.
	return -1;
}

CPoint CCardStack::VGetNextPosition() const
{
	CPoint position;

	if(IsEmpty() && m_lerpingCards.empty()) {
		return m_position;
	}
	else if(m_eDirection == keDown) {
		position = CPoint(m_position.m_iX, m_position.m_iY + (Size() + m_lerpingCards.size() - 1) * m_iOffset);
	}
	else if(m_eDirection == keRight) {
		position = CPoint(m_position.m_iX + (Size() + m_lerpingCards.size() - 1)  * m_iOffset, m_position.m_iY);
	}
	else if(m_eDirection == keBoth) {
		position = CPoint(m_position.m_iX + (Size() + m_lerpingCards.size() - 1) * m_iOffset,  
						  m_position.m_iY + (Size() + m_lerpingCards.size() - 1) * m_iOffset);
	}

	return position;
}

void CCardStack::VUpdatePositions()
{
	CPoint currentPosition;

	for(int i = 0; i < Size(); ++i) {
		if(m_eDirection == keDown) {
			currentPosition = CPoint(m_position.m_iX, m_position.m_iY + i * m_iOffset);
		}
		else if(m_eDirection == keRight) {
			currentPosition = CPoint(m_position.m_iX + i * m_iOffset, m_position.m_iY);
		}
		else if(m_eDirection == keBoth) {
			currentPosition = CPoint(m_position.m_iX + i * m_iOffset,  
									 m_position.m_iY + i * m_iOffset);
		}

		m_cards[i].SetPosition(currentPosition);
	}
}

bool CCardStack::CanBePushed(const CPlayingCard& _krCard)
{
	return true;
}

bool CCardStack::CanBePushed(const CCardStack& _krStack)
{
	return true;
}

void CCardStack::Push(const CPlayingCard& _krCard)
{
	// Push the card onto the stack.
	m_cards.push_back(_krCard);

	// Update the positions of the cards.
	VUpdatePositions();
}

void CCardStack::Push(const TStack& _krStack)
{
	for(unsigned int i = 0; i < _krStack.size(); ++i) {
		m_cards.push_back(_krStack[i]);
	}

	VUpdatePositions();
}

void CCardStack::PushLerping(const CPlayingCard& _krCard)
{
	// Push the card onto the stack.
	m_lerpingCards.push_back(_krCard);
}

void CCardStack::PushLerping(const TStack& _krStack)
{
	for(unsigned int i = 0; i < _krStack.size(); ++i) {
		m_lerpingCards.push_back(_krStack[i]);
	}
}

void CCardStack::PopLerping()
{
	m_lerpingCards.pop_front();
}

void CCardStack::Pop()
{
	m_cards.pop_back();
}

TStack CCardStack::PopStack(int _iIndex) 
{
	TStack newStack;

	// Transfer cards to newstack.
	for(int i = _iIndex; i < Size(); ++i) {
		newStack.push_back(m_cards[i]);
	}

	int iSizeTemp = Size();

	// Remove cards from this stack.
	for(int i = _iIndex; i < iSizeTemp; ++i) {
		m_cards.pop_back();
	}

	return newStack;
}

CCardStack CCardStack::PopSubStack(int _iIndex)
{
	CCardStack subStack;

	// Transfer member variables
	subStack.SetOffset(m_iOffset);
	subStack.SetDirection(m_eDirection);
	subStack.SetPosition(m_position);
	subStack.Push(PopStack(_iIndex));

	return subStack;
}

void CCardStack::Shuffle()
{
	// Shuffle the cards randomly.
	std::random_shuffle(m_cards.begin(), m_cards.end());

	// Reset all positions.
	VUpdatePositions();
}

void CCardStack::Clear()
{
	m_cards.clear();
}

bool CCardStack::IsEmpty() const
{
	return m_cards.empty();
}

int CCardStack::Size() const
{
	return static_cast<int>(m_cards.size());
}

const TStack& CCardStack::GetStack() const
{
	return m_cards;
}

CPlayingCard& CCardStack::operator[](int _iIndex)
{
	return m_cards[_iIndex];
}

const CPlayingCard& CCardStack::operator[](int _iIndex) const
{
	return m_cards[_iIndex];
}

CPlayingCard& CCardStack::Peek()
{
	return m_cards.back();
}

const CPlayingCard& CCardStack::Peek() const
{
	return m_cards.back();
}

void CCardStack::SetOffset(int _iOffset)
{
	m_iOffset = _iOffset;
}

void CCardStack::SetPosition(const CPoint& _krPosition)
{
	m_position = _krPosition;

	VUpdatePositions();
}

void CCardStack::SetDirection(EStackDirection _eDirection)
{
	m_eDirection = _eDirection;
}

int CCardStack::GetOffset() const
{
	return m_iOffset;
}

const CPoint& CCardStack::GetPosition() const 
{
	return m_position;
}

CRect CCardStack::GetTopRect() const
// Retrieves the rectangle of the top card.
{
	if(!IsEmpty()) {
		return Peek().GetRect();
	}
	else {
		return CRect(m_position.m_iX, m_position.m_iY, g_kiCARD_WIDTH, g_kiCARD_HEIGHT);
	}
}

const EStackDirection& CCardStack::GetDirection() const
{
	return m_eDirection;
}